﻿using System;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Isuka.Reflection;

namespace Isuka.Linq
{
    /// <summary>
    /// クエリープロバイダー
    /// </summary>
    public abstract class QueryProvider
        : IQueryProvider
    {
        public abstract string GetQueryText(Expression expression);

        public abstract object Execute(Expression expression);

        #region IQueryProvider メンバー

        public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
        {
            Gate.RequireNotNull(expression);
            return new Query<TElement>(this, expression);
        }

        [ContractVerification(false)]
        public IQueryable CreateQuery(Expression expression)
        {
            Gate.RequireNotNull(expression, "expression");

            var elemType = TypeHelper.GetElementType(expression.Type);
            try
            {
                var type = typeof(Query<>).MakeGenericType(elemType);
                return (IQueryable)Activator.CreateInstance(type, new object[] { this, expression });
            }
            catch (TargetInvocationException ex)
            {
                throw ex.InnerException;
            }
        }

        TResult IQueryProvider.Execute<TResult>(Expression expression)
        {
            return (TResult)Execute(expression);
        }

        object IQueryProvider.Execute(Expression expression)
        {
            return Execute(expression);
        }

        #endregion
    }
}
